#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<signal.h>
#include<arpa/inet.h>
#include<netdb.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
#include<sys/stat.h>
#include <sys/time.h>
#include <time.h>
#include <string.h>
#include <memory.h>

#define DATAOPEN  true
#define DATACLOSE false

// Globa variables
void *TransSocketThread(void* );
 void *SocketTransThread2(void*);

pthread_mutex_t mutex;


typedef struct {
   int m_SocketSrc;
   int m_SocketDest;
}T_AddrPort;

char m_Buf[512*1024] = {0}; // 缓冲区--暂存

int m_MainId = 0; // Main ID
int m_ListenSocket = 0; // Listen Socket -- Client
char m_ConnectAddr[256] = {0}; // Server IP
char m_ConnectPort[10] = {0}; // Server Port


// data socket
int m_ProxySocket = 0;
char m_DataConnectPort[10] = {0};
int nServerPort;
int  nProxyPort;
bool flag = DATACLOSE;
/*
 *  1. 生成一个侦听client的套接字
 */
int GetListenSocket(int nPort)
{
     // 本地地址
        struct sockaddr_in m_LisAddr = {0};
        int    m_Socket = 0;
        int    m_AddrLen = sizeof(struct sockaddr_in);

        m_LisAddr.sin_family = AF_INET;
        m_LisAddr.sin_port = htons(nPort);
        m_LisAddr.sin_addr.s_addr = INADDR_ANY;

     // Socket
        if((m_Socket = socket(AF_INET, SOCK_STREAM,0))<0){
               return 0;  // 创建失败
        }
     // bind Socket
        if(bind(m_Socket, (struct sockaddr*)&m_LisAddr, m_AddrLen)<0){
               return 0;  // 绑定失败
        }
     // listen Socket
        if(listen(m_Socket, 5)){
               close(m_Socket); // !important
               return 0;   // 监听失败
        }
        return m_Socket;
}

/*
 *  2. 获取Ftp服务器的Socket -- 这个以后要换成读取地址和端口列表（多个Socket)
 */
int  GetConnectSocket(char* pServerAddr, char* pServerPort)
{
         struct sockaddr_in m_ServerAddr = {0};
         int    m_AddrLen = sizeof(struct sockaddr_in);
         int    m_Socket = 0;
      // 初始化连接信息
         m_ServerAddr.sin_addr.s_addr = inet_addr(pServerAddr);
         m_ServerAddr.sin_port = htons(atoi(pServerPort));
         m_ServerAddr.sin_family = AF_INET;
      // 创建套接字
         m_Socket = socket(AF_INET, SOCK_STREAM, 0);
         if(m_Socket <=0){
               return 0; // 创建失败
         }
      // 连接
         if(connect(m_Socket,(struct sockaddr*)&m_ServerAddr, m_AddrLen)<0){
               close(m_Socket); // !important
               return 0;
         }
         return m_Socket;
}

/*
 *  3. 两个套接字之间的数据暂存与转发--这里就实现了代理的功能
 */
void TransSocket( int m_SendSocket, int m_RecvSocket)
{
        char m_Buf[512*1024] = {0}; // 缓冲区--暂存
        int  ret = 0;

        struct timeval tm = {0};
        tm.tv_sec = 3600*24;

        fd_set  readset;
        FD_ZERO(&readset);
        FD_SET(m_RecvSocket, &readset);
        while(1){
             if((select(m_RecvSocket+1, &readset, NULL, NULL, &tm)<=0)){
                   break;
             }
             if(!FD_ISSET(m_RecvSocket,&readset))
                   continue;
             printf("Data!--From:%d\n", m_RecvSocket);
             // 从m_RecvSocket,接收数据
             ret = recv(m_RecvSocket, m_Buf, 512*1024-1, 0);
             printf("%s\n",m_Buf);
             if(ret <0){
                   break; // 接受Ftp服务器数据失败
             }
             // 将接收到的数据传给客户端
             send(m_SendSocket, m_Buf,ret,0);
        }
        close(m_SendSocket);
        close(m_RecvSocket);
}

/**
 *   3.1 线程函数
 */
void *TransSocketThread(void* pArgs)
{
        T_AddrPort *pAddrPort = (T_AddrPort*)pArgs;
        int m_SendSocket = pAddrPort->m_SocketSrc;
        int m_RecvSocket = pAddrPort->m_SocketDest;

        int  ret = 0;

        struct timeval tm = {0};
        tm.tv_sec = 3600*24;

        fd_set  readset;
        FD_ZERO(&readset);
        FD_SET(m_RecvSocket, &readset);
        while(1){
          // lock
             //pthread_mutex_lock(&mutex);

             if((select(m_RecvSocket+1, &readset, NULL, NULL, &tm)<=0)){
                   break;
             }
             if(!FD_ISSET(m_RecvSocket,&readset))
                   continue;
             printf("Data!--From:%d\n", m_RecvSocket);
             // 从m_RecvSocket,接收数据
             ret = recv(m_RecvSocket, m_Buf, 512*1024-1, 0);
             printf("%s\n",m_Buf);
             if(ret <0){
                   break; // 接受Ftp服务器数据失败
             }
             // 将接收到的数据传给客户端
             send(m_SendSocket, m_Buf,ret,0);

              // release-lock
             //pthread_mutex_unlock(&mutex);
             //sleep(2);
        }
        delete pAddrPort;
}

/**
 *   3.2 线程函数 -- 截获数据建立的端口
 */
void *TransSocketThread2(void* pArgs)
{
        T_AddrPort *pAddrPort = (T_AddrPort*)pArgs;
        int m_SendSocket = pAddrPort->m_SocketSrc;
        int m_RecvSocket = pAddrPort->m_SocketDest;

        int  ret = 0;

        struct timeval tm = {0};
        tm.tv_sec = 3600*24;

        fd_set  readset;
        FD_ZERO(&readset);
        FD_SET(m_RecvSocket, &readset);
        while(1){
          // lock
             //pthread_mutex_lock(&mutex);

             if((select(m_RecvSocket+1, &readset, NULL, NULL, &tm)<=0)){
                   break;
             }
             if(!FD_ISSET(m_RecvSocket,&readset))
                   continue;
             printf("Data!--From:%d\n", m_RecvSocket);
             // 从m_RecvSocket,接收数据
             ret = recv(m_RecvSocket, m_Buf, 512*1024-1, 0);

             if(ret <0){
                   break; // 接受Ftp服务器数据失败
             }
             printf("%s\n",m_Buf);
             // 对数据进行处理 !Important -- 暂时只处理这种情况
             // 227 Entering Passive Mode (192,168,56,1,19,214)
             if(strncmp(m_Buf,"227",3)==0){
                   // 开始修改 -- 端口
                   char *p1 = m_Buf + ret;
                   while(*p1 != ')')
                       p1--;
                   char *p2 = p1;
                   while(*p2!=',')
                       p2--;
                   char numBuf[8];
                   memset(numBuf,'\0',8);
                   strncpy(numBuf,p2+1, p1-p2+1);
                   int num_back = atoi(numBuf);
                   p1 = p2-1;
                   while(*p1!=',')
                       p1--;
                   memset(numBuf,'\0',8);
                   strncpy(numBuf,p1+1, p2-p1-1);
                   int num_fore = atoi(numBuf);
                   nServerPort = num_fore*256+num_back;
                   char tempStr[10];
                   sprintf(tempStr, "%d", nServerPort);
                   strcpy(m_DataConnectPort, tempStr);
                   printf("\n\t:%d:\n",nServerPort);

                   // 开始修改返回数据的端口
                // 1. 代理服务器开的端口
                   char  pProxyIP[20] = "10,0,2,15";
                   nProxyPort = 4007;
                   int   nProxyPortFore = nProxyPort/256;
                   int   nProxyPortBack = nProxyPort%256;
                   char  strProxyPortForeFore[5];
                   char  strProxyPortForeBack[5];
                   sprintf(strProxyPortForeFore,"%d",nProxyPortFore);
                   sprintf(strProxyPortForeBack,"%d",nProxyPortBack);
                   // 接下来修改m_Buf的端口等等数据
                   p1 = m_Buf + ret;
                   p2 = m_Buf;
                   int n1=0, n2=0;
                   while(*p1!=')'){
                      p1--;
                      n1++;
                   }
                   while(*p2!='('){
                      p2++;
                      n2++;
                   }
                   char tempBuf[512*1024];
                   strncpy(tempBuf, m_Buf, n2+1);
                   strcat(tempBuf,pProxyIP);
                   strcat(tempBuf,",");
                   strcat(tempBuf,strProxyPortForeFore);
                   strcat(tempBuf,",");
                   strcat(tempBuf,strProxyPortForeBack);
                   strcat(tempBuf,p1);
                   /*
                   printf("---------------------\n");
                   printf("::%s::\n",tempBuf);
                   printf("---------------------\n");
                   */
                   //send(m_SendSocket, tempBuf,strlen(tempBuf),0);
                   //continue;
                   strcpy(m_Buf,tempBuf);
                   ret = strlen(tempBuf);

                   m_ProxySocket = GetListenSocket(nServerPort);
                   if(m_ProxySocket == 0){
                        printf("-------------word------------------\n");
                        printf("Data Listen [%d] error!\n",nProxyPort);
                        fflush(stdout);
                        pthread_exit(0);
                   }
                   // 开始数据连接线程
                   //SocketTransThread2();
                   pthread_t pid;
                   pthread_create(&pid, NULL, SocketTransThread2,NULL);
                   sleep(10);

             }

             /*
             if(strncmp(m_Buf,"LIST",4)==0){
                   // 2. 建立侦听
                   printf("-------------hello------------------\n");
                   m_ProxySocket = GetListenSocket(nServerPort);
                   if(m_ProxySocket == 0){
                        printf("-------------word------------------\n");
                        printf("Data Listen [%d] error!\n",nProxyPort);
                        fflush(stdout);
                        pthread_exit(0);
                   }
                   printf("-------------xiaoqiang------------------\n");
                   // 开始数据连接线程
                   SocketTransThread2();
             }
             */
             /*
             if(flag == DATAOPEN){
                   m_ProxySocket = GetListenSocket(nServerPort);
                   if(m_ProxySocket == 0){
                        printf("-------------word------------------\n");
                        printf("Data Listen [%d] error!\n",nProxyPort);
                        fflush(stdout);
                        pthread_exit(0);
                   }
                   // 开始数据连接线程
                   //SocketTransThread2();
                   pthread_t pid;
                   pthread_create(&pid, NULL, SocketTransThread2,NULL);
             }
             */
             // 将接收到的数据传给客户端
             send(m_SendSocket, m_Buf,ret,0);
          // release-lock
             //pthread_mutex_unlock(&mutex);
             //sleep(2);
        }
        delete pAddrPort;
}

/*
 *  4. 主逻辑，完成侦听Socket和服务器Socket，并完成他们之间的数据接收和转发
 *     没有接收命令哇
 */
void  SocketTrans()
{
         struct sockaddr_in m_WorkAddr = {0};
         int    m_191Socket = 0;
         int    m_147Socket = 0;
         int    m_WorkAddrLen = 0;

      // 使用得到的侦听socket，获取客户端信息
         while(1){
             // accept -- 侦听端口，客户端Socket
                m_WorkAddrLen = sizeof(struct sockaddr_in);
                m_147Socket = accept(m_ListenSocket,(struct sockaddr*)&m_WorkAddr,(socklen_t*)&m_WorkAddrLen);
                if(m_147Socket<0)
                   continue;
                printf("Cool,Get in!\n");
             // 服务器Ftp的Socket，使用第2个函数
                m_191Socket = GetConnectSocket(m_ConnectAddr, m_ConnectPort);
                if(m_191Socket==0){
                     close(m_147Socket); // !important
                     continue;
                }
             // 开始客户端Socket(m_147Socket)-》服务器Socket(m_191Socket)发送数据（命令）
                TransSocket(m_147Socket,m_191Socket);
                printf("Send--Mission Complete!");
                TransSocket(m_191Socket,m_147Socket);
                printf("Recv-Mission Complete!");
         }
         close(m_191Socket);
         close(m_147Socket);
}

/**
 *  4.1 适合于线程的主函数
 */
 void SocketTransThread()
 {
         struct sockaddr_in m_WorkAddr = {0};
         int    m_191Socket = 0;
         int    m_147Socket = 0;
         int    m_WorkAddrLen = 0;
         m_WorkAddrLen = sizeof(struct sockaddr_in);
         m_147Socket = accept(m_ListenSocket,(struct sockaddr*)&m_WorkAddr,(socklen_t*)&m_WorkAddrLen);
         if(m_147Socket<0)
                return;
         printf("Cool,Get in!\n");
      // 服务器Ftp的Socket，使用第2个函数
         m_191Socket = GetConnectSocket(m_ConnectAddr, m_ConnectPort);
         if(m_191Socket==0){
                close(m_147Socket); // !important
                return;
         }
      // 构造传递的参数
         T_AddrPort *temp1 = new T_AddrPort;
         temp1->m_SocketSrc = m_147Socket;
         temp1->m_SocketDest = m_191Socket;

         T_AddrPort *temp2 = new T_AddrPort;
         temp2->m_SocketSrc = m_191Socket;
         temp2->m_SocketDest = m_147Socket;
      // 线程互斥
         pthread_mutex_init(&mutex, NULL);

         pthread_t pid1,pid2;
         pthread_create(&pid1, NULL, TransSocketThread2, (void*)temp1);
         pthread_create(&pid2, NULL, TransSocketThread2, (void*)temp2);

      // 阻塞-等待线程结束
         pthread_join(pid1, NULL);
         pthread_join(pid2, NULL);
         close(m_147Socket);
         close(m_191Socket);
 }

 /**
  *   4.2 适合数据连接的主函数
  */
 void *SocketTransThread2(void *pArgs)
 {
         struct sockaddr_in m_WorkAddr = {0};
         int    m_192Socket = 0;
         int    m_148Socket = 0;
         int    m_WorkAddrLen = 0;
         m_WorkAddrLen = sizeof(struct sockaddr_in);
         printf("-----------------Cool, More---------!\n");
         m_148Socket = accept(m_ProxySocket,(struct sockaddr*)&m_WorkAddr,(socklen_t*)&m_WorkAddrLen);
         if(m_148Socket<0)
                pthread_exit(0);
         printf("-----------------Cool, Data---------!\n");
      // 服务器Ftp的Socket，使用第2个函数
         m_192Socket = GetConnectSocket(m_ConnectAddr, m_DataConnectPort);
         if(m_192Socket==0){
                close(m_148Socket); // !important
                pthread_exit(0);
         }
      // 构造传递的参数
         T_AddrPort *temp1 = new T_AddrPort;
         temp1->m_SocketSrc = m_148Socket;
         temp1->m_SocketDest = m_192Socket;

         T_AddrPort *temp2 = new T_AddrPort;
         temp2->m_SocketSrc = m_192Socket;
         temp2->m_SocketDest = m_148Socket;

         pthread_t pid1,pid2;
         pthread_create(&pid1, NULL, TransSocketThread2, (void*)temp1);
         pthread_create(&pid2, NULL, TransSocketThread2, (void*)temp2);

      // 阻塞-等待线程结束
         pthread_join(pid1, NULL);
         pthread_join(pid2, NULL);
         close(m_148Socket);
         close(m_192Socket);
 }


/*
 *  You Know, Let's Do it!!
 */
int main(int argc, char* argv[])
{
      char* pArgv[] = {
         "",
         "4000",
         "192.168.56.1",
         "21"
       };
       strcpy(m_ConnectAddr, pArgv[2]);
       strcpy(m_ConnectPort, pArgv[3]);
    // listen
       m_ListenSocket = GetListenSocket(atoi(pArgv[1]));
       if(m_ListenSocket == 0){
            printf("Listen [%s] error!\n",pArgv[1]);
            fflush(stdout);
            return 0;
       }
    // start
       SocketTransThread();
       close(m_ListenSocket);
       printf("Hi, man,done!");
       return 0;
}
